home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockMyworldService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
19KB
|
602 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
// TODO JVL: queue is now a stack but the syntax continues to use 'queue'. Will fix later.
// XPConnect Helpers
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
// Constants
const MYWORLD_SHORTNAME = "myworld";
const MYWORLD_FULLNAME = "Myworld";
const MYWORLD_TITLE = "Myworld Service";
const MYWORLD_FAVICON = "http://www.flock.com/favicon.ico";
const MYWORLD_CID = Components.ID("{bb35349f-fb23-3089-4d3d-28462e1c98eb}");
const MYWORLD_CONTRACTID = "@flock.com/myworld-service;1";
const CATEGORY_COMPONENT_NAME = "Myworld JS Component";
const CACHESERVICE_CONTRACTID = "@mozilla.org/network/cache-service;1";
const TIMER_CONTRACTID = "@mozilla.org/timer;1";
const XMLHTTPREQUEST_CONTRACTID = "@mozilla.org/xmlextras/xmlhttprequest;1";
const MAX_FLICKR_FARMS = 10;
const PROTOCOL = "http://";
const FLICKR_FARM = "farm";
const MAX_RETRIEVAL_ATTEMPTS = 3;
const DEFAULT_INTERVAL = 500; // in milliseconds
const DEFAULT_TIMER_TYPE = Ci.nsITimer.TYPE_REPEATING_PRECISE;
// Component Utils (just used for the timer/scheduler)
var gCompTK;
function getCompTK() {
if (!gCompTK) {
var gCompTK = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
.wrappedJSObject;
}
return gCompTK;
}
// ===========================================================
// ========== BEGIN flockMyworldService Component ============
// ===========================================================
// BEGIN Constructor
function myworldService()
{
this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
this._logger.init("MyworldService");
this._logger.debug("BEGIN Ctor");
this._queue = [];
this._ctk = {
interfaces: [
"nsISupports",
"nsIClassInfo",
"nsISupportsCString",
"nsIObserver",
"flockIMyworldService"
],
shortName: MYWORLD_SHORTNAME,
fullName: MYWORLD_FULLNAME,
description: MYWORLD_TITLE,
favicon: MYWORLD_FAVICON,
CID: MYWORLD_CID,
contractID: MYWORLD_CONTRACTID
};
this.obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
this.obs.addObserver(this, "xpcom-shutdown", false);
this.obs.addObserver(this, "flock-data-ready", false);
this._coop = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var inst = this; // this is necessary as you cannot use 'this' within the defined notify function
var callback = { notify : function(aTimer) { inst.processQueue(); } };
this._timer = Components.classes[TIMER_CONTRACTID].createInstance(Ci.nsITimer);
this._timer.initWithCallback(callback, DEFAULT_INTERVAL, DEFAULT_TIMER_TYPE);
this._logger.info("Myworld service created");
this._logger.debug("END Ctor");
}
// END Constructor
myworldService.prototype.init =
function myworldService_init()
{
var loosePhotosEnum = this._coop.RichPhoto.all();
while (loosePhotosEnum.hasMoreElements()) {
var photo = loosePhotosEnum.getNext();
if (!photo.cachedThumbnail || photo.cachedThumbnail == "") {
this.queueResource(photo.id());
}
}
}
// BEGIN nsIObserver
myworldService.prototype.observe = function (subject, topic, data)
{
if (topic == "xpcom-shutdown")
{
this.obs.removeObserver(this, "xpcom-shutdown");
} else if (topic == "flock-data-ready") {
this.obs.removeObserver(this, "flock-data-ready");
this.init();
}
}
// END nsIObserver
// BEGIN flockIMyworldService
myworldService.prototype.flags = Ci.nsIClassInfo.SINGLETON;
// queue a unique resource for processing
myworldService.prototype.queueResource =
function myworldService_queueResource(aURN)
{
this._logger.debug("BEGIN queueResource: " + aURN);
if (!this.queueResourceExists(aURN))
{
this.createQueueResource(aURN);
}
this._logger.debug("END queueResource: " + aURN);
}
// clear the queue
myworldService.prototype.clearQueue =
function myworldService_clearQueue()
{
while(this._queue.length > 0)
{
this._queue.shift();
}
this._logger.info("queue cleared");
}
// check the browser cache for the given key
// returns a valid cached key or null if not found
myworldService.prototype.checkCache =
function myworldService_checkCache(aKey)
{
this._logger.debug("BEGIN checkCache: " + aKey);
if (aKey)
{
var cacheSession = this.getCacheSession();
if (cacheSession)
{
// check in the browser cache for the given key
if (this.isValidCacheEntry(cacheSession, aKey))
{
this._logger.debug("END checkCache: " + aKey);
return aKey;
}
// we couldn't find the given resource in the browser cache, it may have been forwarded to a farm...
// trim the url(key) for our search needs and search for this modified url(key)
var keyBase = aKey;
if (aKey.indexOf(PROTOCOL) == 0)
{
keyBase = aKey.substr(PROTOCOL.length);
}
for (var idx = 1; idx < MAX_FLICKR_FARMS + 1; idx++)
{
var key = PROTOCOL + FLICKR_FARM + idx + "." + keyBase;
if (this.isValidCacheEntry(cacheSession, key))
{
this._logger.debug("END checkCache: " + key);
return key;
}
}
}
}
this._logger.debug("END checkCache: null");
return null;
}
// END flockIMyworldService
// BEGIN flockMyworldService
// returns the cache session or null if an error occured
myworldService.prototype.getCacheSession =
function myworldService_getCacheSession()
{
var cacheService = Cc[CACHESERVICE_CONTRACTID].getService(Ci.nsICacheService);
if (!cacheService)
{
this._logger.debug("getCacheSession: No cache service");
return null;
}
// check both memory and disk cache
// NOTE: 'HTTP' is the name for the browser cache
var cacheSession = cacheService.createSession("HTTP", Ci.nsICache.STORE_ANYWHERE, true);
if (!cacheSession)
{
this._logger.debug("getCacheSession: No cache session");
return null;
}
cacheSession.doomEntriesIfExpired = false;
return cacheSession;
}
// check that the given key is in the browser cache
// returns true if found, false otherwise
myworldService.prototype.isValidCacheEntry =
function isValidCacheEntry(cacheSession, aKey)
{
this._logger.debug("BEGIN isValidCacheEntry: " + aKey);
if (!cacheSession)
{
this._logger.debug("END isValidCacheEntry: No cache session");
return false;
}
if (!aKey || aKey.length < 1)
{
this._logger.debug("END isValidCacheEntry: No key supplied");
return false;
}
try
{
// checks browser cache for given key(url)
// found if a cacheEntryDescriptor is returned and the resource's size is > 0,
// otherwise it will throw an exception
var cacheEntryDescriptor = cacheSession.openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, false);
var found = this.isNonEmptyResource(cacheEntryDescriptor);
var msg = "END isValidCacheEntry: openCacheEntry: " + aKey + (found ? " (found in cache)" : " (not found in cache)");
this._logger.debug(msg);
return found;
}
catch (ex)
{
this._logger.debug("isValidCacheEntry: " + aKey + " (not in cache)");
}
this._logger.debug("END isValidCacheEntry: false");
return false;
}
// helper function to determine if the cacheEntryDescriptor is:
// 1) not null
// 2) size > 0
// also reports additional details if showDetails = true
// returns true if it passes the above criteria, false otherwise
myworldService.prototype.isNonEmptyResource =
function isNonEmptyResource(cacheEntryDescriptor, showDetails)
{
if (showDetails)
this._logger.debug("isNonEmptyResource:");
// NOTE: when checking cacheEntryDescriptor for nullness, we need to check it explictly against null. '!cacheEntryDescriptor' will not work!
var found = (cacheEntryDescriptor != null);
if (showDetails)
this._logger.debug(" descriptor: " + (found ? "not null" : "null"));
var size = cacheEntryDescriptor.dataSize;
if (showDetails)
this._logger.debug(" size: " + size);
return found && (size > 0);
}
// process the elements stored in the queue
myworldService.prototype.processQueue =
function processQueue()
{
var elem = null;
var coopObj = null;
var thumbnail = null;
while (1)
{
//this._logger.debug("BEGIN processQueue: current queue size: " + this._queue.length);
if (this._queue.length < 1)
{
//this._logger.debug("END processQueue: nothing in the queue to process");
return;
}
// pop the first entry off the queue for processing
elem = this._queue.shift();
if (!elem)
{
this._logger.debug("END processQueue: element popped off queue is null, nothing to process");
return;
}
this._logger.debug("processQueue:");
this._logger.debug(" processing: " + elem.urn);
this._logger.debug(" items left in queue: " + this._queue.length);
// retrieve the appropriate resource from the rdf in memory
coopObj = this._coop.get(elem.urn);
if (!coopObj)
{
this._logger.debug("END processQueue: " + elem.urn + " (not in rdf)");
return;
}
thumbnail = coopObj.thumbnail;
this._logger.debug("processQueue: thumbnail: " + thumbnail);
// if the retrieved resource doesn't have topmedia as a parent,
// discard from the queue and just set the regular thumbnail in hopes it can show something
if (this.belongsToTopMedia(coopObj))
{
this._logger.debug("processQueue: " + elem.urn + " (found in topmedia)");
break;
}
else
{
this._logger.debug("processQueue: " + elem.urn + " (not in topmedia, process the next item in the queue)");
coopObj.cachedThumbnail = thumbnail;
}
}
// we only need to update the rdf with the cachedThumbnail if it doesn't already exist
if (!this.isValidCachedThumbnail(coopObj.cachedThumbnail, thumbnail))
{
// take a look in the browser cache for the cached thumbnail url
thumbnail = this.checkCache(thumbnail);
if (thumbnail)
{
this._logger.debug("processQueue: " + thumbnail + " (in cache)");
// found the cached thumbnail url, now store it in the rdf; we're done!
coopObj.cachedThumbnail = thumbnail;
}
else
{
this._logger.debug("processQueue: " + coopObj.thumbnail + " (not in cache)");
coopObj.cachedThumbnail = "";
// we couldn't find the cached thumbnail url in the browser cache so retrieve the resource
// from the social service to see if we can cache it ourselves and retrieve it later
this.reRequestResource(coopObj.thumbnail);
this._logger.debug("processQueue: re-add to queue:");
this._logger.debug(" URN: " + elem.urn);
this._logger.debug(" current attempt: " + elem.attempt);
// since it wasn't in the browser cache this time, re-add the queued entry to the end of the
// queue; we will try retrieving it later (for a maximum of MAX_RETRIEVAL_ATTEMPTS) otherwise,
// just fail as there might be something wrong with the social service itself
this.requeueResource(elem, coopObj)
}
}
this._logger.debug("END processQueue");
}
// checks to see if the coop object has a topmedia as a parent
// returns true if topmedia is a parent, false otherwise
myworldService.prototype.belongsToTopMedia =
function myworldService_belongsToTopMedia(coopObj)
{
if (!coopObj)
{
return false;
}
var parents = coopObj.getParents();
if (!parents)
{
return false;
}
for (var idx in parents)
{
var parent = parents[idx];
if (parent)
{
var grandParents = parent.getParents();
if (grandParents)
{
for (var idxGP in grandParents)
{
var grandParent = grandParents[idxGP];
if (grandParent.id() == "urn:flock:topmedia")
{
this._logger.debug("belongsToTopMedia: belongs to topmedia!");
return true;
}
}
}
}
}
return false;
}
// check if the cachedThumbnail is:
// 1) not null or empty and
// 2) not the loading picture
// returns true if the cachedThumbnail passes the above criteria, false otherwise
myworldService.prototype.isValidCachedThumbnail =
function myworldService_isValidCachedThumbnail(cachedThumbnail, thumbnail)
{
return cachedThumbnail && cachedThumbnail.length > 0;
}
// re-retrieve the resource from the social service to see if we can cache it ourselves and retrieve it later
myworldService.prototype.reRequestResource =
function myworldService_reRequestResource(thumbnail)
{
this._logger.debug("BEGIN reRequestResource");
if (thumbnail)
{
var request = Cc[XMLHTTPREQUEST_CONTRACTID].createInstance(Ci.nsIXMLHttpRequest);
if (!request)
{
this._logger.debug("END reRequestResource: unable to instantiate HTTPRequest");
return;
}
try
{
this._logger.debug("reRequestResource: HTTPRequest sent for " + thumbnail);
request.open("GET", coopObj.thumbnail, true);
request.send(null);
}
catch (ex)
{
this._logger.debug("reRequestResource: HTTPRequest failed for " + thumbnail);
}
}
this._logger.debug("END reRequestResource");
}
// requeue the resource unless the maximum attempts to retrieve the resource has been exceeded
myworldService.prototype.requeueResource =
function myworldService_requeueResource(elem, coopObj)
{
this._logger.debug("BEGIN requeueResource");
elem.attempt++;
if (elem.attempt < MAX_RETRIEVAL_ATTEMPTS)
{
this._queue.unshift(elem);
this._logger.debug("requeueResource: " + elem.urn + " (re-added to queue successfully)");
}
else
{
// number of attempts exceeded, just set the displayed thumbnail to the original resource
coopObj.cachedThumbnail = coopObj.thumbnail;
this._logger.debug("requeueResource: " + elem.urn + " (not re-added to queue as we've already tried " + MAX_RETRIEVAL_ATTEMPTS + " times)");
}
this._logger.debug(" number of items in queue: " + this._queue.length);
this._logger.debug("END requeueResource");
}
// check if the resource already exists in the queue to be processed
// returns false if it is unique to the queue, true otherwise
myworldService.prototype.queueResourceExists =
function myworldService_queueResourceExists(aURN)
{
this._logger.debug("BEGIN queueResourceExists: " + aURN);
if (!aURN || aURN.length < 1)
{
this._logger.debug("END queueResourceExists: true (empty string)");
return true;
}
// ensure we don't add duplicates to the queue
// NOTE: This may become an issue if there are an excessive number of items in the queue
for (var idx = 0; idx < this._queue.length; idx++)
{
if (this._queue[idx].urn == aURN)
{
this._logger.debug("END queueResourceExists: true (already exists)");
return true;
}
}
this._logger.debug("END queueResourceExists: false");
return false;
}
// create a new resource and add it to the service queue to be processed
myworldService.prototype.createQueueResource =
function myworldService_createQueueResource(aURN)
{
if (aURN && aURN.length > 0)
{
// add a new url/retrieval attempts (key/value) pair to the queue
var obj = {};
obj.urn = aURN;
obj.attempt = 0;
this._logger.debug("createQueueResource:");
this._logger.debug(" URN: " + obj.urn);
this._logger.debug(" attempt: " + obj.attempt);
this._queue.unshift(obj);
}
}
// END flockMyworldService
// ========== END flockMyworldService Component ============
// ================================================
// ========== BEGIN XPCOM Module support ==========
// ================================================
const ENABLE_DEBUG = false; // switch to turn off slow debug code for production
function DEBUG(x) { if (ENABLE_DEBUG) debug("flockMyworldService: "+x+"\n"); }
function createModule(aParams) {
DEBUG("createModule called\n CID: " + aParams.CID + "\n componentName: " + aParams.componentName + "\n contractID: " + aParams.contractID + "\n componentClass: " + aParams.componentClass);
return {
registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
aParams.contractID, aFileSpec,
aLocation, aType );
var catMgr = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
catMgr.addCategoryEntry( "flock-startup", aParams.componentName,
"service,"+aParams.contractID, true, true );
if (!aParams.categories) { aParams.categories = []; }
for (var i = 0; i < aParams.categories.length; i++) {
var cat = aParams.categories[i];
catMgr.addCategoryEntry( cat.category, cat.entry,
cat.value, true, true );
}
},
getClassObject: function (aCompMgr, aCID, aIID) {
if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
return { // Factory
createInstance: function (aOuter, aIID) {
if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
var comp = new aParams.componentClass();
if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
rv = comp.QueryInterface(aIID);
return rv;
}
};
},
canUnload: function (aCompMgr) { return true; }
};
}
// NS Module entrypoint
function NSGetModule(aCompMgr, aFileSpec) {
DEBUG("NSGetModule called");
return createModule({
componentClass: myworldService,
CID: MYWORLD_CID,
contractID: MYWORLD_CONTRACTID,
componentName: CATEGORY_COMPONENT_NAME,
implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
categories: [
]
});
}
// ========== END XPCOM Module support ==========